package org.dxy.domain.model.aggregate.factory.impl;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dxy.domain.port.repository.IProductionLineRepository;
import org.dxy.domain.port.repository.IRouteRepository;
import org.dxy.domain.command.workorder.CreateWorkOrderCommand;
import org.dxy.domain.model.aggregate.factory.WorkOrderFactory;
import org.dxy.domain.model.aggregate.WorkOrder;
import org.springframework.stereotype.Component;

/**
 * 工单工厂实现类
 * @author dxy
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class WorkOrderFactoryImpl implements WorkOrderFactory {
    
    private final IRouteRepository routeRepository;
    private final IProductionLineRepository productionLineRepository;
    
    @Override
    public WorkOrder create(Long workOrderId, CreateWorkOrderCommand command) {
        log.info("开始创建工单聚合根, workOrderId={}, command={}", workOrderId, command);
        
        // 1. 业务规则验证
        validateBusinessRules(command);
        
        // 2. 创建工单聚合根
        WorkOrder workOrder = WorkOrder.create(workOrderId, command);
        
        log.info("工单聚合根创建成功, workOrderId={}", workOrderId);
        return workOrder;
    }
    
    /**
     * 验证业务规则
     * @param command 创建工单命令
     */
    private void validateBusinessRules(CreateWorkOrderCommand command) {
        // 1. 校验工艺路线是否存在且可用（如果指定了）
        if (command.routeId() != null) {
            if (!routeRepository.existsById(command.routeId())) {
                throw new IllegalArgumentException("工艺路线不存在: " + command.routeId());
            }
            if (!routeRepository.isActive(command.routeId())) {
                throw new IllegalArgumentException("工艺路线已停用: " + command.routeId());
            }
        }
        
        // 2. 校验产线是否存在且可用（如果指定了）
        if (command.productionLineId() != null) {
            if (!productionLineRepository.existsById(command.productionLineId())) {
                throw new IllegalArgumentException("产线不存在: " + command.productionLineId());
            }
            if (!productionLineRepository.isAvailable(command.productionLineId())) {
                throw new IllegalArgumentException("产线不可用（可能在维护中）: " + command.productionLineId());
            }
        }
        
        // 3. 校验工艺路线与产线的兼容性（如果都指定了）
        if (command.routeId() != null && command.productionLineId() != null) {
            if (!routeRepository.isCompatibleWithProductionLine(command.routeId(), command.productionLineId())) {
                throw new IllegalArgumentException(
                    String.format("工艺路线 %d 与产线 %d 不兼容", command.routeId(), command.productionLineId())
                );
            }
        }
        
        // 4. 校验返工工单的特殊规则
        if (command.isReworkOrder()) {
            validateReworkOrderRules(command);
        }
        
        // 5. 校验计划时间的合理性
        if (command.hasPlannedTime()) {
            validatePlannedTimeRules(command);
        }
        
        log.debug("工单业务规则验证通过, command={}", command);
    }
    
    /**
     * 验证返工工单的特殊业务规则
     * @param command 创建工单命令
     */
    private void validateReworkOrderRules(CreateWorkOrderCommand command) {
        Long originalWorkOrderId = command.originalWorkOrderId();
        
        // 返工工单必须有原工单ID（这个在Command的validate方法中已经检查过了）
        if (originalWorkOrderId == null) {
            throw new IllegalArgumentException("返工工单必须指定原工单ID");
        }
        
        // TODO: 这里可以添加更多返工工单的业务规则，比如：
        // - 原工单必须存在且状态允许返工
        // - 返工数量不能超过原工单的完成数量
        // - 返工工单的产品必须与原工单一致
        // 由于这些需要额外的Repository方法，暂时注释掉
        
        log.debug("返工工单业务规则验证通过, originalWorkOrderId={}", originalWorkOrderId);
    }
    
    /**
     * 验证计划时间的业务规则
     * @param command 创建工单命令
     */
    private void validatePlannedTimeRules(CreateWorkOrderCommand command) {
        // 计划开始时间不能是过去时间（允许当天）
        if (command.plannedStartTime() != null) {
            if (command.plannedStartTime().isBefore(java.time.LocalDate.now())) {
                throw new IllegalArgumentException("计划开始时间不能早于今天");
            }
        }
        
        // 如果指定了产线，检查产线在计划时间段内的可用性
        if (command.productionLineId() != null && 
            command.plannedStartTime() != null && 
            command.plannedEndTime() != null) {
            
            if (!productionLineRepository.isAvailableInTimeRange(
                    command.productionLineId(), 
                    command.plannedStartTime(), 
                    command.plannedEndTime())) {
                throw new IllegalArgumentException(
                    String.format("产线 %d 在时间段 %s 到 %s 内不可用", 
                        command.productionLineId(),
                        command.plannedStartTime(),
                        command.plannedEndTime())
                );
            }
        }
        
        log.debug("计划时间业务规则验证通过, plannedStartTime={}, plannedEndTime={}", 
                 command.plannedStartTime(), command.plannedEndTime());
    }

}